#light

(* XPathNavigator based cgxml implementation.  This does not need the schema proc in order to
perform the datatype lookup systems, although it does the schema information.

After doing a bit of research, it appears the fastest way to load read-only xml
is using an xpath document.  Most documents in a multi-document system will
be read only, at least most of the time.  Hopefully, operations using msxml's
xpath and schema system should be robust and quite quick.

Given a set of schemas, when you load a document it should be fully or mostly
checked against a schema.  The xpath system should use the schema in order to
create some new nodes and there will be systems built on top that walk through
the datatypes; so they can find all id's in a document, for instance.

Doing XML this way seems a lot smarter than the naive way, and it seems to be
perfect for large systems where you don't need to know about most of the data.

Tests should include datatype lookups, ensuring that node creation gets a new
schema item so that default values and new id's can be recorded, and checking out
how the intermixing of schema documents works for items embedded in other documents.*)

//xp means x path, not extreme performance.
module CGraph.CGXmlXp
open System.Xml
open System.Xml.XPath
open System.Xml.Schema
open Microsoft.FSharp.Collections
open CGraph.Generic.Impl
open CGraph.Generic
open CGraph.Generic.Algorithms

type DocumentGroup(m_schemas:XmlSchemaSet) =
    let mutable m_documents = Map<string,DocGroupEntry>.Empty()
    
    /// The beauty of functional data structures, I don't have to worry
    /// about returning the data structure.  It is immutable.
    member s.Documents = m_documents
            
            
    ///Load a new document.  IF read only is true, then write
    ///operations made to the document will throw exceptions.
    ///Returns true of the document was already loaded, else it
    ///loads the document and returns false
    member s.GetOrLoadDocument (path,readOnlyFlag) =
        let item = m_documents.TryFind( path )
        match item with
            | Some dgd -> true
            | None ->
                //Build xml reader.
                let settings = XmlReaderSettings()
                settings.Schemas <- m_schemas
                settings.ValidationType <- ValidationType.Schema
                let reader = XmlReader.Create (path,settings)
                let Document = 
                    let xmlDoc = XmlDocument()
                    xmlDoc.Load(reader)
                    xmlDoc
                
                m_documents <- m_documents.Add( path, { Handles=HandleMap<XmlNode>();Document=Document } )
                false
                
    member private s.NavAndHandles path =
        let doc = m_documents.[path]
        let elem = doc.Document.DocumentElement :> XmlNode
        elem,doc.Handles
   
    member private s.Navigator path hdl =
        let nav,handles = s.NavAndHandles path
        handles.[hdl]
        
                
    member s.FindDatatypes (path,types,callback) =
        let nav,handles = s.NavAndHandles path 
        FindDatatypes types handles nav callback
        
    member s.GetValue (path,hdl) =
        let nav = s.Navigator path hdl
        XmlNodeValue nav